package com.zmj.demo.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;

import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.IndexRequest;

import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.ElasticsearchIndicesClient;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.zmj.framework.exception.business.BizException;
import com.zmj.framework.request.PageRequest;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @Author MG
 * @Date 2024/4/8 15:03
 * @Version 1.0
 */
@Component
@Slf4j
public class EsOperate {

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private ElasticsearchIndicesClient indicesClient;


    /**
     * 存在索引
     *
     * @param index 指数
     * @return boolean
     * @throws IOException IOException
     */
    @SneakyThrows
    public boolean existsIndex(String index) {
        BooleanResponse booleanResponse = indicesClient.exists(e -> e.index(index));
        log.info("index exists {}", booleanResponse.value());
        return booleanResponse.value();
    }


    /**
     * 创建索引
     *
     * @param index 指数
     * @return boolean
     * @throws IOException IOException
     */
    public boolean createIndex(String index) throws IOException {
        boolean flag = existsIndex(index);
        boolean result = false;
        if (flag) {
            // 目标索引已存在
            log.info("索引【" + index + "】已存在！");
        } else {
            // 不存在
            result = indicesClient.create(req -> req.index(index)).acknowledged();
            if (result) {
                log.info("索引【" + index + "】创建成功！");
            } else {
                log.info("索引【" + index + "】创建失败！");
            }
        }
        return result;
    }

    @SneakyThrows
    public void insertIndex(String index, String data) {

        if (!JSONUtil.isJson(data)) {
            log.error("字符串不是JSON {}", data);
            throw new BizException("字符串不是JSON");
        }
        createIndex(index);
        BulkRequest.Builder br = new BulkRequest.Builder();
        boolean isArray = JSONUtil.isJsonArray(data);
        if (isArray) {
            JSONArray jsonArray1 = JSONUtil.parseArray(data);
            Iterator<Object> it = jsonArray1.iterator();
            while (it.hasNext()) {
                JSONObject ob = (JSONObject) it.next();
                if (ob.getStr("id") != null) {
                    br.operations(op -> op
                            .index(idx -> idx
                                    .index(index)
                                    .id(ob.getStr("id"))
                                    .document(ob)));
                }
            }
        }
        boolean isObj = JSONUtil.isJsonObj(data);
        if (isObj) {
            JSONObject jsonObject = JSONUtil.parseObj(data);
            if (jsonObject.getStr("id") != null) {
                br.operations(op -> op
                        .index(idx -> idx
                                .index(index)
                                .id(jsonObject.getStr("id"))
                                .document(jsonObject)));
            }
        }

        BulkResponse result = elasticsearchClient.bulk(br.build());
        // Log errors, if any
        if (result.errors()) {
            log.error("Bulk had errors");
            StringBuilder errorBuilder = new StringBuilder();
            for (BulkResponseItem item : result.items()) {
                if (item.error() != null) {
                    log.error(item.error().reason());
                    errorBuilder.append(item.error().reason());
                }
            }
            throw new BizException("批量保存报错: "+errorBuilder);
        }


    }


    @SneakyThrows
    public List<Map<String, Object>> query(PageRequest pageRequest, String index) {
        // 分页查询
        SearchResponse<Map> test = elasticsearchClient.search(s -> s
                .index("test")
                .query(q -> q
                        .matchAll(m -> m)
                ).sort(sort -> sort
                        .field(f -> f
                                .field(pageRequest.getOrderBy())
                                .order(SortOrder.Desc)
                        )
                )
                .from(pageRequest.getCurrent())
                .size(pageRequest.getSize()), Map.class);

        List<Map<String, Object>> list = new ArrayList<>();
        if (CollUtil.isEmpty(test.hits().hits())) {
            return list;
        }
        for (Hit<Map> hit : test.hits().hits()) {
            list.add(hit.source());
        }
//        System.out.println(newapi.took());
//        System.out.println(newapi.hits().total().value());
//        newapi.hits().hits().forEach(e -> System.out.println(e.source().toString()));

        return list;
    }


}
